package com.audaque.springboot.foshanupload.casclientautoconfigsupport.listener;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.net.ssl.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;

/**
 * @author zgb
 * @desc
 * 实现ApplicationRunner接口和实现CommandLineRunner接口基本是一样的。
 * 唯一的不同是启动时传参的格式，CommandLineRunner对于参数格式没有任何限制，ApplicationRunner接口参数格式必须是：–key=value
 * 实现接口ApplicationListener方式和实现ApplicationRunner，CommandLineRunner接口都不影响服务，都可以正常提供服务，注意监听的事件，通常是ApplicationStartedEvent 或者ApplicationReadyEvent，其他的事件可能无法注入bean。
    注解方式@PostConstruct 始终最先执行
    如果监听的是ApplicationStartedEvent 事件，则一定会在CommandLineRunner和ApplicationRunner 之前执行。
    如果监听的是ApplicationReadyEvent 事件，则一定会在CommandLineRunner和ApplicationRunner 之后执行。
    CommandLineRunner和ApplicationRunner 默认是ApplicationRunner先执行，如果双方指定了@Order 则按照@Order的大小顺序执行，大的先执行。
 */
@Component
@Slf4j
public class CasClientAutoConfigSupportAfterAllBeanInitedListener implements CommandLineRunner, ApplicationRunner, ApplicationListener<ApplicationReadyEvent> {

    @PostConstruct
    public void init() throws InterruptedException {
        log.debug("PostConstruct");
    }

    @Override
    public void run(String... args) throws Exception {
        log.debug("CommandLineRunner:在所有 Spring Beans 初始化完成之后执行");


    }
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.debug("ApplicationRunner:在所有 Spring Beans 初始化完成之后执行");
        // 这段代码用于解决报错  java.security.cert.CertificateException: No name matching server.ssodemo.com found
        disableSslVerification();
    }

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        log.debug("ApplicationListener<ApplicationReadyEvent>");
    }


    private  void disableSslVerification() {
        try{
            // Create a trust manager that does not validate certificate chains
            TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
                public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType)
                        throws CertificateException {
                }
                public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType)
                        throws CertificateException {
                }
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            }
            };
            // Install the all-trusting trust manager
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            // Create all-trusting host name verifier
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
            // Install the all-trusting host verifier
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }

    }

}
